import torch
import torch.nn as nn
import torch.optim as optim
import matplotlib.pyplot as plt


# 定义输入和目标数据
X = torch.tensor([-1.0, 0.0, 1.0, 2.0, 3.0, 4.0]).unsqueeze(1)  # 输入数据
y = torch.tensor([-3.0, -1.0, 1.0, 3.0, 5.0, 7.0]).unsqueeze(1)  # 目标数据

# 定义单层感知机模型
class Perceptron(nn.Module):
    def __init__(self):
        super(Perceptron, self).__init__()
        self.fc = nn.Linear(1, 1)

    def forward(self, x):
        return self.fc(x)

# 定义多层感知机模型
class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.fc1 = nn.Linear(1, 2)
        self.fc2 = nn.Linear(2, 1)

    def forward(self, x):
        x = torch.relu(self.fc1(x))
        return self.fc2(x)

# 使用 GPU 训练单层感知机模型
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print("Using device:", device)

perceptron_model = Perceptron().to(device)
criterion = nn.MSELoss()
optimizer = optim.SGD(perceptron_model.parameters(), lr=0.01)

perceptron_losses = []
for epoch in range(500):
    optimizer.zero_grad()
    outputs = perceptron_model(X.to(device))
    loss = criterion(outputs, y.to(device))
    loss.backward()
    optimizer.step()
    perceptron_losses.append(loss.item())
    if (epoch+1) % 50 == 0:
        print(f"Epoch [{epoch+1}/500], Loss: {loss.item():.4f}")
# 保存单层感知机模型参数
torch.save(perceptron_model.state_dict(), "perceptron_model.pth")
print("Saved perceptron model to perceptron_model.pth")

# 使用 GPU 训练多层感知机模型
net_model = Net().to(device)
optimizer = optim.SGD(net_model.parameters(), lr=0.01)

net_losses = []
for epoch in range(500):
    optimizer.zero_grad()
    outputs = net_model(X.to(device))
    loss = criterion(outputs, y.to(device))
    loss.backward()
    optimizer.step()
    net_losses.append(loss.item())
    if (epoch+1) % 50 == 0:
        print(f"Epoch [{epoch+1}/500], Loss: {loss.item():.4f}")
# 保存多层感知机模型参数
torch.save(net_model.state_dict(), "net_model.pth")
print("Saved net model to net_model.pth")

# 绘制训练过程中的损失曲线
plt.plot(range(500), perceptron_losses, label='Perceptron')
plt.plot(range(500), net_losses, label='Net')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.legend()
plt.show()